package internal

import (
	"fmt"
	"net"
	"os"
	"serverlog/global"
	"serverlog/src/internal/icode"
)

type Server struct {
	//绑定端口
	port uint32
	//通知消息,这里统一处理写入文件啥的
	notify chan iinternal.INotifyMsg
	//会话管理
	sesAdmin iinternal.ISessionAdmin
	//默认打印控制台级别
	level uint32
	//默认打印目录
	logpath string
	//默认文件大小限制
	filesize uint32
	file0    string
	file1    string
	loginit  bool
}

func NewServer(port uint32) iinternal.IServer {
	s := &Server{
		port:     port,
		notify:   make(chan iinternal.INotifyMsg, 10000),
		sesAdmin: NewSessionAdmin(),
		level:    global.ServerGlobal.Level,
		logpath:  global.ServerGlobal.LogPath,
		filesize: global.ServerGlobal.FileSize,
		loginit:  false,
	}

	//初始化一个协程专门处理消息
	go s.notifyProc()

	return s
}

func file_clean(file string) {
	f, err := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil {
		return
	}
	f.Close()
}

//根据日志大小限制做文件回滚切换
func (s *Server) switchPath() string {
	if !s.loginit {
		s.loginit = true
		s.file0 = s.logpath + "/log0.txt"
		s.file1 = s.logpath + "/log1.txt"
	}
	f0, err0 := os.Stat(s.file0)
	f1, err1 := os.Stat(s.file1)

	//如果0不存在,就是它了
	if err0 != nil {
		return s.file0
	}
	if err1 != nil {
		//如果1不存在的情况下,看下0有没有超过限制
		if uint32(f0.Size()) < s.filesize {
			return s.file0
		}
		return s.file1
	}
	//都存在的情况下,取最新修改的文件,如果超过限制就清空并选另一个文件
	if f0.ModTime().Unix() > f1.ModTime().Unix() {
		if uint32(f0.Size()) > s.filesize {
			file_clean(s.file1)
			return s.file1
		}
		return s.file0
	}
	if uint32(f1.Size()) > s.filesize {
		file_clean(s.file0)
		return s.file0
	}
	return s.file1
}

//保存文件
func (s *Server) logSave(msg iinternal.INotifyMsg) {
	path := s.switchPath()

	f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		fmt.Println("openfile err=", err, "path=")
		return
	}
	defer f.Close()

	f.Write([]byte(msg.GetMsg()))
}

func (s *Server) notifyProc() {
	for {
		select {
		case notify, ok := <-s.notify:
			if !ok {
				return
			}
			level := notify.GetLevel()
			if level <= s.level {
				fmt.Println(notify.GetMsg())
			}
			s.logSave(notify)
		}
	}
}

func (s *Server) Run() {
	fmt.Println("start serverlog run!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
	//先绑定sock
	addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf(":%d", s.port))
	if err != nil {
		fmt.Println("resolvetcpaddr err=", err)
		return
	}

	//监听
	listener, err := net.ListenTCP("tcp", addr)
	if err != nil {
		fmt.Println("listtcp err=", err)
		return
	}

	//accept
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listener err=", err)
			return
		}
		//这里可能要做下会话个数限制
		if s.sesAdmin.GetSessionNums() >= global.ServerGlobal.MaxConnections {
			conn.Close()
			continue
		}
		s := s.sesAdmin.NewSession(conn, s.notify)
		go s.Run()
	}
}
